package cn.mandy.sysadmin.service.impl;

import cn.mandy.sysadmin.common.api.MandyRuntimeException;
import cn.mandy.sysadmin.common.api.ResultCode;
import cn.mandy.sysadmin.common.util.MandyTree;
import cn.mandy.sysadmin.component.AuthenticationUser;
import cn.mandy.sysadmin.constant.MandyConstant;
import cn.mandy.sysadmin.dao.MandyDictFrontEndDao;
import cn.mandy.sysadmin.dao.MandyPanelDao;
import cn.mandy.sysadmin.dao.MandyRoleMenuDao;
import cn.mandy.sysadmin.dao.MandyUserWithRolesDao;
import cn.mandy.sysadmin.dto.*;
import cn.mandy.sysadmin.mapper.*;
import cn.mandy.sysadmin.model.*;
import cn.mandy.sysadmin.service.MandyCacheService;
import cn.mandy.sysadmin.service.MandyService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * MandyService的实现类
 * 负责权限资源,角色,用户的数据设置类型的操作
 * Created by Winter
 */
@Service
public class MandyServiceImpl implements MandyService {
    private static final Logger LOGGER = LoggerFactory.getLogger(MandyServiceImpl.class);

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private MandyPermissionMapper mandyPermissionMapper;

    @Autowired
    private MandyRolePermissionMapper mandyRolePermissionMapper;

    @Autowired
    private MandyRolePermParamMapper mandyRolePermParamMapper;

    @Autowired
    private MandyDictFrontEndDao mandyDictFrontEndDao;

    @Autowired
    private MandyRoleMapper mandyRoleMapper;

    @Autowired
    private MandyRoleMenuDao mandyRoleMenuDao;

    @Autowired
    private MandyUserWithRolesDao mandyUserWithRolesDao;

    @Autowired
    private MandyUserMapper mandyUserMapper;

    @Autowired
    private MandyUserRoleMapper mandyUserRoleMapper;

    @Autowired
    private MandyDepartmentMapper mandyDepartmentMapper;

    @Autowired
    private MandyPanelDao mandyPanelDao;

    @Autowired
    private MandyPermParamMapper mandyPermParamMapper;

    @Autowired
    private MandyParameterMapper mandyParameterMapper;

    @Autowired
    private AuthenticationUser authenticationUser;

    @Autowired
    private MandyCacheService mandyCacheService;

    @Override
    public List<MandyPermission> listAllAuditedPanels() {
        MandyPanelListParam panelListParam = new MandyPanelListParam();
        panelListParam.setAuditState(MandyConstant.AuditState.CHECKED);
        List<MandyPermission> panels = mandyPanelDao.listPanel(panelListParam);
        return MandyTree.listToTree(panels);
    }

    @Override
    public List<MandyPermission> listAllMenuGroups() {
        List<String> param = new ArrayList<>();
        param.add(MandyConstant.PermType.MENU_GROUP);
        MandyPermissionExample mandyPermissionExample = new MandyPermissionExample();
        mandyPermissionExample.createCriteria().andPermTypeIn(param);
        return MandyTree.listToTree(mandyPermissionMapper.selectByExample(mandyPermissionExample));
    }

    @Override
    public List<MandyPermission> panelList(MandyPanelListParam panelListParam) {
        List<MandyPermission> panels = mandyPanelDao.listPanel(panelListParam);
        return MandyTree.listToTree(panels);
    }

    private void insertFunctions(List<MandyPermission> children, Long parentId){
        if (null == children){
            return;
        }

        for (MandyPermission child: children) {
            child.setParentId(parentId);
            child.setId(null);
            child.setAuditState(MandyConstant.AuditState.UNCHECKED);

            //TODO 参数的获取, 是由url反查的, 所以必须保证设置了参数的url是唯一的,
            //不存在二义性
            //if (null != child.getParameters() && ! child.getParameters().isEmpty()){
            if (null != child.getParameterIds() && ! child.getParameterIds().isEmpty()){
                MandyPermissionExample mandyPermissionExample = new MandyPermissionExample();
                mandyPermissionExample.createCriteria().andNameEqualTo(child.getName());
                List<MandyPermission> permissions = mandyPermissionMapper.selectByExample(mandyPermissionExample);
                if (null != permissions && !permissions.isEmpty() ){
                    //throw new RuntimeException("有参数配置的URL不允许重复");
                    throw new MandyRuntimeException(ResultCode.DATA_UNIQUE);
                }

                //child.setHasParameter("1");
                mandyPermissionMapper.insert(child);
                MandyPermParam mandyPermParam = new MandyPermParam();
                mandyPermParam.setPermissionId(child.getId());
                //for (MandyRolePermParam param: child.getParameters()){
                //    mandyPermParam.setParameterId(param.getParameterId());
                //前端用 parameterIds
                for (String paramId: child.getParameterIds()){
                    mandyPermParam.setParameterId(Long.valueOf(paramId));
                    mandyPermParam.setId(null);
                    mandyPermParamMapper.insert(mandyPermParam);
                }
            } else{
                //child.setHasParameter("0");
                mandyPermissionMapper.insert(child);
            }
        }
    }

    @Override
    @Transactional
    public int panelCopy(MandyPermission panel) {
        int ret;
        panel.setAuditState(MandyConstant.AuditState.UNCHECKED);
        panel.setId(null);
        ret = mandyPermissionMapper.insert(panel);
        if (ret != 1){
            return ret;
        }
        insertFunctions(panel.getChildren(),panel.getId());

        return 0;
    }

    @Override
    @Transactional
    public int panelUpdate(MandyPermission panel) {
        //面板和功能的设置, 是系统中的根基, 不能随意的变动
        //如果已经有角色在使用此面板，
        //即在 sys_mm_role_menu 下有此面板的数据(不论sys_mm_role_menu 中的status和iz_allowed是什么值), 不允许再修改.
        //如果遇版本升级, 面板功能设计上与原先版本的不一样, 只能是将先将原先的面板禁用
        //重新调整角色的菜单权限, 从所有角色的菜单中删除此面板, 添加新的面板.
        //最后对原面板作一个下架修改, 在备注中添加下架说明
        MandyPermission mandyPermission = mandyPermissionMapper.selectByPrimaryKey(panel.getId());
        if (null == mandyPermission || MandyConstant.AuditState.CHECKED.equals(mandyPermission.getAuditState())) {
            return 0;
        }

        MandyRolePermissionExample mandyRoleMenuExample = new MandyRolePermissionExample();
        mandyRoleMenuExample.createCriteria().andPermissionIdEqualTo(panel.getId());
        List<MandyRolePermission> mandyRolePermissions = mandyRolePermissionMapper.selectByExample(mandyRoleMenuExample);
        if (null != mandyRolePermissions && ! mandyRolePermissions.isEmpty() ){
            return 0;
        }

        //满足 1, 禁用状态, 2 在 MandyRoleMenuMapper 中没有数据才能更新
        //删除原有的子结点数据(面板下的功能)
        //FIXME 同时要删除参数
        MandyPermissionExample mandyPermissionExample = new MandyPermissionExample();
        mandyPermissionExample.createCriteria().andParentIdEqualTo(panel.getId());
        mandyPanelDao.deletePanelParameter(panel.getId()); //先删除参数,再删除原来的功能
        mandyPermissionMapper.deleteByExample(mandyPermissionExample);

        //更新面板数据
        panel.setAuditState(MandyConstant.AuditState.UNCHECKED);
        mandyPermissionMapper.updateByPrimaryKey(panel);
        //插入新的功能
        insertFunctions(panel.getChildren(), panel.getId());

        return 1;
    }

    @Override
    @Transactional
    public int panelAudit(MandyPermission panel) {
        //启用状态下的面板只允许禁用, 不允许修改
        //禁用状态下的面板，允许重新启用。
        //要同时对面板下的功能更新audit_status;
        MandyPermission mandyPermission = mandyPermissionMapper.selectByPrimaryKey(panel.getId());
        if (null == mandyPermission){
            return 0;
        }
        //本来就一样，没有变更，直接返回
        if (mandyPermission.getAuditState().equals(panel.getAuditState())){
            return 1;
        }
        mandyPermission.setAuditState(panel.getAuditState());
        mandyPermissionMapper.updateByPrimaryKey(mandyPermission);

        //要同时对面板下的功能更新audit_status;
        MandyPermission permission = new MandyPermission();
        permission.setAuditState(panel.getAuditState());
        MandyPermissionExample mandyPermissionExample = new MandyPermissionExample();
        mandyPermissionExample.createCriteria().andParentIdEqualTo(panel.getId());
        mandyPermissionMapper.updateByExampleSelective(permission, mandyPermissionExample);

        return 1;
    }

//    @Override
//    @Transactional
//    public int panelDelete(Long panelId) {
//        MandyRolePermissionExample example = new MandyRolePermissionExample();
//        example.createCriteria().andPermissionIdEqualTo(panelId);
//
//        List<MandyRolePermission> mandyRolePermissionList = mandyRolePermissionMapper.selectByExample(example);
//        if (null == mandyRolePermissionList || mandyRolePermissionList.isEmpty()){
//            MandyPermissionExample toBeDeleteExample = new MandyPermissionExample();
//            toBeDeleteExample.createCriteria().andParentIdEqualTo(panelId);
//            //删除面板下的功能
//            mandyPermissionMapper.deleteByExample(toBeDeleteExample);
//            //删除面板本身
//            mandyPermissionMapper.deleteByPrimaryKey(panelId);
//        } else{
//            // 有菜单在使用，不能删除
//            return 1;
//        }
//        return 0;
//    }

    @Override
    public List<MandyRole> roleList() {
        MandyRoleExample mandyRoleExample = new MandyRoleExample();
        return mandyRoleMapper.selectByExample(mandyRoleExample);
    }

    @Override
    public MandyRoleDetail getRoleMenuForUpdate(Long roleId) {
        List<MandyRoleResource> empty = new ArrayList<>();

        MandyRoleDetail mandyRoleMenuForUpdate =  new MandyRoleDetail();
        MandyRole mandyRole = mandyRoleMapper.selectByPrimaryKey(roleId);
        mandyRoleMenuForUpdate.setMandyRole(mandyRole);

        if (MandyConstant.AuditState.UPDATING.equals(mandyRole.getAuditState())) {  // 更新状态,需要返回两组菜单
            mandyRoleMenuForUpdate.setInUsed(MandyTree.listToTree(
                    mandyRoleMenuDao.getRoleMenuPermissionList(roleId, MandyConstant.AuditState.CHECKED)));
            mandyRoleMenuForUpdate.setNewCandidate(MandyTree.listToTree(
                    mandyRoleMenuDao.getRoleMenuPermissionList(roleId, MandyConstant.AuditState.UNCHECKED)));
        }else if (MandyConstant.AuditState.CHECKED.equals(mandyRole.getAuditState() )){
            mandyRoleMenuForUpdate.setInUsed(MandyTree.listToTree(
                    mandyRoleMenuDao.getRoleMenuPermissionList(roleId, mandyRole.getAuditState())));
            mandyRoleMenuForUpdate.setNewCandidate(empty);
        }else if (MandyConstant.AuditState.UNCHECKED.equals(mandyRole.getAuditState())){
            mandyRoleMenuForUpdate.setInUsed(empty);
            mandyRoleMenuForUpdate.setNewCandidate(MandyTree.listToTree(
                    mandyRoleMenuDao.getRoleMenuPermissionList(roleId, mandyRole.getAuditState())));
        }

        return mandyRoleMenuForUpdate;
    }

    @Override
    @Transactional
    public MandyRoleMenuGroup createMenuGroup(MandyRoleMenuGroup mandyRoleMenuGroup) {
        MandyPermission mandyPermission = new MandyPermission();
        mandyPermission.setAuditState(MandyConstant.AuditState.CHECKED);
        mandyPermission.setParentId(0L);
        mandyPermission.setPermType(MandyConstant.PermType.MENU_GROUP);
        mandyPermission.setTitle(mandyRoleMenuGroup.getTitle());
        mandyPermission.setIconClass(mandyRoleMenuGroup.getIconClass());
        mandyPermission.setRemark(mandyRoleMenuGroup.getRemark());

        mandyPermissionMapper.insert(mandyPermission);
        mandyRoleMenuGroup.setId(mandyPermission.getId());

        return mandyRoleMenuGroup;
    }

    private void roleCopyUpdateParentId(Long oldParentId, Long newParentId, List<MandyRolePermission> mandyRolePermissions){
        for (MandyRolePermission record: mandyRolePermissions) {
            if (record.getParentId().equals(oldParentId)){
                record.setParentId(newParentId);
            }
        }
    }

    @Override
    @Transactional
    public int roleCopy(MandyRole mandyRole) {
        Long srcId = mandyRole.getId();
        mandyRole.setId(null);
        mandyRole.setTitle(mandyRole.getTitle());
        mandyRole.setRemark(mandyRole.getRemark());
        mandyRole.setAuditState(MandyConstant.AuditState.UNCHECKED);
        int ret = mandyRoleMapper.insert(mandyRole);
        if (ret != 1){
            return 0;
        }

        MandyRolePermissionExample mandyRoleMenuExample = new MandyRolePermissionExample();
        mandyRoleMenuExample.createCriteria().andRoleIdEqualTo(srcId);
        List<MandyRolePermission> mandyRolePermissions =  mandyRolePermissionMapper.selectByExample(mandyRoleMenuExample);
        for (MandyRolePermission record: mandyRolePermissions ) {
            Long oldId = record.getId();
            record.setId(null);
            record.setRoleId(mandyRole.getId());
            record.setAuditState(MandyConstant.AuditState.UNCHECKED);
            mandyRolePermissionMapper.insert(record);
            roleCopyUpdateParentId(oldId, record.getId(), mandyRolePermissions);
        }

        return 1;
    }

    private void roleNewCandidateUpdateParentId(Long oldParentId, Long newParentId, List<MandyRoleResource> mandyRolePermissions){
        for (MandyRoleResource record: mandyRolePermissions) {
            if (record.getParentId().equals(oldParentId)){
                record.setParentId(newParentId);
            }
        }
    }

    @Override
    @Transactional
    public MandyRole roleUpdate(List<MandyRoleResource> mandyRoleResources) {
        MandyUserDetail user = authenticationUser.getCurrentMmUser();
        List<MandyRoleResource> myList = MandyTree.treeToList(mandyRoleResources);
        if (myList == null || myList.isEmpty()){
            return null;
        }
        Long roleId = myList.get(0).getRoleId();

        MandyRole mandyRole = mandyRoleMapper.selectByPrimaryKey(roleId);
        if (null == mandyRole){
            return null;
        }

        //TODO 加上创建人，复核人员信息
        if (MandyConstant.AuditState.CHECKED.equals(mandyRole.getAuditState()) ) {
            mandyRole.setCreateUserId(user.getMandyUser().getId());
            mandyRole.setCreateUserName(user.getMandyUser().getName());
            mandyRole.setCreateTime(new Date());

            mandyRole.setAuditState(MandyConstant.AuditState.UPDATING);
            mandyRoleMapper.updateByPrimaryKey(mandyRole);
        }else {
            MandyRolePermissionExample mandyRoleMenuExample = new MandyRolePermissionExample();
            mandyRoleMenuExample.createCriteria()
                    .andRoleIdEqualTo(roleId)
                    .andAuditStateEqualTo(MandyConstant.AuditState.UNCHECKED);
            //DELETE PARAMETERS FIRST!
            mandyRoleMenuDao.deleteRolePermParameters(roleId, MandyConstant.AuditState.UNCHECKED);
            mandyRolePermissionMapper.deleteByExample(mandyRoleMenuExample);
        }

        for (MandyRoleResource record: myList){
            MandyRolePermission mandyRolePermission = record.getMandyRolePermission();
            Long oldId = mandyRolePermission.getId();
            mandyRolePermission.setId(null);
            mandyRolePermission.setRoleId(roleId);
            mandyRolePermission.setAuditState(MandyConstant.AuditState.UNCHECKED);
            mandyRolePermissionMapper.insert(mandyRolePermission);
            roleNewCandidateUpdateParentId(oldId, mandyRolePermission.getId(), myList);
            MandyPermission mandyPermission = record.getMandyPermission();
            //设置参数值, TODO user_id, signature etc.
            if (null != mandyPermission.getParameters() && ! mandyPermission.getParameters().isEmpty()){
                for (MandyRolePermParam param: mandyPermission.getParameters()) {
                    if (null != param.getValue() && !param.getValue().isEmpty()) {
                        param.setRolePermissionId(mandyRolePermission.getId());
                        mandyRolePermParamMapper.insert(param);
                    }
                }
            }
        }

        return mandyRole;
    }

    private void cacheEvictAboutRole(Long roleId){
        mandyCacheService.cacheEvictListUserRolesEntries();
        mandyCacheService.cacheEvictListMandyAuthorityByRoleId(roleId);
        mandyCacheService.cacheEvictGetRoleMainMenu(roleId);
        mandyCacheService.cacheEvictGetRoleById(roleId);
        mandyCacheService.cacheEvictGetParametersEntries();
    }

    @Override
    @Transactional
    public MandyRole roleEnable(MandyRole mandyRole) {
        MandyRole newRole = mandyRoleMapper.selectByPrimaryKey(mandyRole.getId());
        if (newRole.getAuditState().equals(MandyConstant.AuditState.CHECKED)){
            return null;
        }

        //需要删除掉原有的启用菜单, 再将更新的菜单设置为启用状态
        MandyRolePermissionExample mandyRolePermissionExample = new MandyRolePermissionExample();
        if (MandyConstant.AuditState.UPDATING.equals(newRole.getAuditState())){
            mandyRolePermissionExample.createCriteria()
                    .andRoleIdEqualTo(newRole.getId())
                    .andAuditStateEqualTo(MandyConstant.AuditState.CHECKED);
            mandyRolePermissionMapper.deleteByExample(mandyRolePermissionExample);

        }
        mandyRolePermissionExample.clear();
        mandyRolePermissionExample.createCriteria()
                .andRoleIdEqualTo(newRole.getId())
                .andAuditStateEqualTo(MandyConstant.AuditState.UNCHECKED);
        MandyRolePermission mandyRolePermissionSelective = new MandyRolePermission();
        mandyRolePermissionSelective.setAuditState(MandyConstant.AuditState.CHECKED);
        mandyRolePermissionMapper.updateByExampleSelective(mandyRolePermissionSelective, mandyRolePermissionExample);

        newRole.setAuditState(MandyConstant.AuditState.CHECKED);
        mandyRoleMapper.updateByPrimaryKey(newRole);

        this.cacheEvictAboutRole(newRole.getId());
        return newRole;
    }

    @Override
    @Transactional
    public MandyRole roleDisable(MandyRole mandyRole) {
        MandyRole newRole = mandyRoleMapper.selectByPrimaryKey(mandyRole.getId());
        if (MandyConstant.AuditState.UNCHECKED.equals(newRole.getAuditState().equals("0"))){
            return null;
        }

        MandyRolePermissionExample mandyRoleMenuExample = new MandyRolePermissionExample();
        if (MandyConstant.AuditState.UPDATING.equals(newRole.getAuditState())){
            mandyRoleMenuExample.createCriteria()
                    .andRoleIdEqualTo(newRole.getId())
                    .andAuditStateEqualTo(MandyConstant.AuditState.UNCHECKED);
            mandyRolePermissionMapper.deleteByExample(mandyRoleMenuExample);
        }

        mandyRoleMenuExample.clear();
        mandyRoleMenuExample.createCriteria()
                .andRoleIdEqualTo(newRole.getId())
                .andAuditStateEqualTo(MandyConstant.AuditState.CHECKED);
        MandyRolePermission mandyRolePermissionSelective = new MandyRolePermission();
        mandyRolePermissionSelective.setAuditState(MandyConstant.AuditState.UNCHECKED);
        mandyRolePermissionMapper.updateByExampleSelective(mandyRolePermissionSelective, mandyRoleMenuExample);

        newRole.setAuditState(MandyConstant.AuditState.UNCHECKED);
        mandyRoleMapper.updateByPrimaryKey(newRole);

        this.cacheEvictAboutRole(newRole.getId());
        return newRole;
    }


    //TODO 要加上权限配置参数的处理
    @Override
    public List<MandyUserWithRoles> listUser(MandyUserWithRolesParam mandyUserWithRolesParam) {
        return mandyUserWithRolesDao.listUser(mandyUserWithRolesParam);
    }

    //TODO 要加上权限配置参数的处理
    @Override
    public Long countUser(MandyUserWithRolesParam mandyUserWithRolesParam) {
        return mandyUserWithRolesDao.countUser(mandyUserWithRolesParam);
    }

    private void setMandyUserCreateInfo(MandyUser mandyUser){
        MandyUserDetail authUser =  authenticationUser.getCurrentMmUser();
        mandyUser.setCreateUserId(authUser.getMandyUser().getId());
        mandyUser.setCreateUserName(authUser.getMandyUser().getName());
        mandyUser.setCreateTime(new Date());
    }

    @Override
    @Transactional
    public MandyUserCreateParam userCreate(MandyUserCreateParam mandyUserCreateParam) {
        List<Long> roleIds = mandyUserCreateParam.getRoleIds();

        if (null == roleIds || roleIds.isEmpty()) {
            return null;
        }

        mandyUserCreateParam.setId(null);

        MandyDepartment department = mandyDepartmentMapper.selectByPrimaryKey(mandyUserCreateParam.getNewDepartmentId());
        mandyUserCreateParam.setDepartmentName(department.getName());
        mandyUserCreateParam.setDepartmentPath(department.getDepartmentPath());
        mandyUserCreateParam.setDepartmentId(department.getId());
        mandyUserCreateParam.setNewDepartmentName(department.getName());

        mandyUserCreateParam.setAuditState(MandyConstant.AuditState.UNCHECKED);
        mandyUserCreateParam.setIzEnabled(MandyConstant.UserIsEnable.ENABLED);
        mandyUserCreateParam.setUserState(MandyConstant.UserState.INITIAL);
        mandyUserCreateParam.setCurrentRoleId(roleIds.get(0));

        setMandyUserCreateInfo(mandyUserCreateParam);
        mandyUserMapper.insert(mandyUserCreateParam);

        mandyUserCreateParam.setUsername(mandyUserCreateParam.getName() + "_" + mandyUserCreateParam.getId());
        mandyUserCreateParam.setPassword(passwordEncoder.encode(mandyUserCreateParam.getUsername()));
        mandyUserMapper.updateByPrimaryKey(mandyUserCreateParam);

        for (Long roleId: mandyUserCreateParam.getRoleIds() ) {
            MandyUserRole mandyUserRole = new MandyUserRole();
            mandyUserRole.setUserId(mandyUserCreateParam.getId());
            mandyUserRole.setRoleId(roleId);
            mandyUserRole.setAuditState(MandyConstant.AuditState.UNCHECKED);

            mandyUserRoleMapper.insert(mandyUserRole);
        }

        return mandyUserCreateParam;
    }

    @Override
    public MandyUserHologram getUserHologramByUserName(String username) {
        MandyUserHologram mandyUserHologram = new MandyUserHologram();
        MandyUserWithRoles mandyUserWithRoles;

        MandyUserWithRolesParam mandyUserWithRolesParam = new MandyUserWithRolesParam();
        mandyUserWithRolesParam.setUsername(username);

        List<MandyUserWithRoles> ret = mandyUserWithRolesDao.listUser(mandyUserWithRolesParam);
        if (null != ret && ret.size() == 1){
            mandyUserWithRoles = ret.get(0);
        }else{
            return null;
        }

        Map<Long, String> userRoles = new HashMap<>();
        for (MandyUserWithRolesMyRoles record: mandyUserWithRoles.getMyRoles()) {
            if ( MandyConstant.AuditState.CHECKED.equals(record.getRelationState()) ){
                userRoles.put(record.getId(), record.getTitle());
            }
        }
        mandyUserHologram.setRoles(userRoles);

        //新建用户/待审核用户  还没有生效的菜单
        mandyUserHologram.setUserInfo(mandyUserWithRoles);
        if ( MandyConstant.UserState.INITIAL.equals(mandyUserWithRoles.getUserState())
                || MandyConstant.UserState.CHECKING.equals(mandyUserWithRoles.getUserState())){
            return mandyUserHologram;
        }

        mandyUserHologram.setMenus(MandyTree.listToTree(
                mandyRoleMenuDao.getRoleMenuPermissionList(mandyUserWithRoles.getCurrentRoleId(), "1")));

        return mandyUserHologram;
    }

    @Override
    public List<MandyDepartment> listDepartment() {
        return MandyTree.listToTree(mandyDepartmentMapper.selectByExample(null));
    }


    @Override
    @Transactional
    public MandyUserWithRoles userDisable(MandyUserWithRoles mandyUserWithRoles) {
        setMandyUserCreateInfo(mandyUserWithRoles);
        mandyUserWithRoles.setNewIsEnabled(MandyConstant.UserIsEnable.DISABLED);
        mandyUserWithRoles.setAuditState(MandyConstant.AuditState.UPDATING);
        //相当于新建用户
        setMandyUserCreateInfo(mandyUserWithRoles);
        mandyUserMapper.updateByPrimaryKey(mandyUserWithRoles);
        return mandyUserWithRoles;
    }

    @Override
    @Transactional
    public MandyUserWithRoles userEnable(MandyUserWithRoles mandyUserWithRoles) {
        setMandyUserCreateInfo(mandyUserWithRoles);
        mandyUserWithRoles.setNewIsEnabled(MandyConstant.UserIsEnable.ENABLED);
        mandyUserWithRoles.setAuditState(MandyConstant.AuditState.UPDATING);
        //相当于新建用户
        setMandyUserCreateInfo(mandyUserWithRoles);
        mandyUserMapper.updateByPrimaryKey(mandyUserWithRoles);
        return mandyUserWithRoles;
    }

    @Override
    @Transactional
    public MandyUserWithRoles userNewDepartment(MandyUserWithRoles mandyUserWithRoles) {
        mandyUserWithRoles.setAuditState(MandyConstant.AuditState.UPDATING);
        mandyUserMapper.updateByPrimaryKey(mandyUserWithRoles);
        //相当于新建用户
        setMandyUserCreateInfo(mandyUserWithRoles);
        return mandyUserWithRoles;
    }

    @Override
    @Transactional
    public MandyUserWithRoles userPasswordReset(MandyUserWithRoles mandyUserWithRoles) {
        MandyUser mandyUser = new MandyUser();
        mandyUser.setId(mandyUserWithRoles.getId());
        mandyUser.setPassword(passwordEncoder.encode(mandyUserWithRoles.getUsername()));
        mandyUser.setUserState(MandyConstant.UserState.RESET);

        //相当于新建用户
        setMandyUserCreateInfo(mandyUser);

        mandyUserMapper.updateByPrimaryKeySelective(mandyUser);
        //重置密码后, 用户登录只能修改密码,
        mandyUserWithRoles.setUserState(MandyConstant.UserState.RESET);
        mandyCacheService.cacheEvictGetMandyUserByName(mandyUserWithRoles.getUsername());
        return mandyUserWithRoles;
    }

    private void setMandyUserAuditInfo(MandyUser mandyUser){
        MandyUserDetail auditUser =  authenticationUser.getCurrentMmUser();
        mandyUser.setAuditUserId(auditUser.getMandyUser().getId());
        mandyUser.setAuditUserName(auditUser.getMandyUser().getName());
        mandyUser.setAuditTime(new Date());
    }


    @Override
    @Transactional
    public MandyUserWithRoles userAudit(MandyUserWithRoles mandyUserWithRoles) {
        MandyUser mandyUser = mandyUserMapper.selectByPrimaryKey(mandyUserWithRoles.getId());

        if (null != mandyUserWithRoles.getNewDepartmentId() ){
            mandyUser.setDepartmentId(mandyUserWithRoles.getNewDepartmentId());
            MandyDepartment department = mandyDepartmentMapper.selectByPrimaryKey(mandyUserWithRoles.getNewDepartmentId());
            mandyUser.setDepartmentName(department.getName());
            mandyUser.setDepartmentPath(department.getDepartmentPath());
            mandyUser.setNewDepartmentId(null);
            mandyUser.setNewDepartmentName(null);
        }

        if (null != mandyUserWithRoles.getNewIsEnabled() && ! mandyUserWithRoles.getNewIsEnabled().isEmpty()){
            mandyUser.setIzEnabled(mandyUserWithRoles.getNewIsEnabled());
            mandyUser.setNewIsEnabled(null);
        }

        if ( MandyConstant.UserState.CHECKING.equals(mandyUserWithRoles.getUserState())){
            mandyUser.setUserState(MandyConstant.UserState.NORMAL);
        }
        //MandyUserMapper.updateByPrimaryKey(MandyUserWithRoles);

        MandyUserRoleExample mandyUserRoleExample = new MandyUserRoleExample();
        mandyUserRoleExample.createCriteria().andUserIdEqualTo(mandyUserWithRoles.getId())
                .andAuditStateEqualTo(MandyConstant.AuditState.UNCHECKED);
        List<MandyUserRole> userRoles = mandyUserRoleMapper.selectByExample(mandyUserRoleExample);

        List<MandyUserWithRolesMyRoles> newMyRoles;
        newMyRoles = mandyUserWithRoles.getMyRoles().stream()
                .filter((role)-> role.getRelationState().equals(MandyConstant.AuditState.UNCHECKED) )
                .collect(Collectors.toList());

        boolean same = false;
        //userRoles, newMyRoles 应该一样
        if (null == userRoles || userRoles.isEmpty()) {
            if (null == newMyRoles || newMyRoles.isEmpty()){
                same = true;
            }
        }else {
            if (null == newMyRoles || newMyRoles.isEmpty()){
                same = false;
            }else if (userRoles.size() != newMyRoles.size()){
                same = false;
            }else {
                int sameCount = 0;
                for (MandyUserRole userRole : userRoles) {
                    boolean find = false;
                    for (MandyUserWithRolesMyRoles newMyRole : newMyRoles) {
                        if (userRole.getRoleId().equals(newMyRole.getId())) {
                            find = true;
                            sameCount ++;
                            break;
                        }
                    }
                    if (!find){
                        break;
                    }
                }

                if (sameCount != userRoles.size()){
                    same = false;
                }else {
                    same = true;
                }
            }
        }

        if (!same){
            throw new MandyRuntimeException(ResultCode.DATA_CONFLICT);
        }

        //新角色为空, 保留原来的角色
        if (null != userRoles && ! userRoles.isEmpty()) {
            //这里默认数据库中的数据是与 mandyUserWithRoles 是一致的
            //即 mandyUserWithRoles 的数据从数据库查出来后直到审核期间没有发生变动.
            mandyUserRoleExample.clear();
            mandyUserRoleExample.createCriteria().andUserIdEqualTo(mandyUserWithRoles.getId())
                    .andAuditStateEqualTo(MandyConstant.AuditState.CHECKED);
            mandyUserRoleMapper.deleteByExample(mandyUserRoleExample);

            mandyUserRoleExample.clear();
            mandyUserRoleExample.createCriteria().andUserIdEqualTo(mandyUserWithRoles.getId())
                    .andAuditStateEqualTo(MandyConstant.AuditState.UNCHECKED);
            MandyUserRole mandyUserRoleSelective = new MandyUserRole();
            mandyUserRoleSelective.setAuditState(MandyConstant.AuditState.CHECKED);
            mandyUserRoleMapper.updateByExampleSelective(mandyUserRoleSelective, mandyUserRoleExample);

            newMyRoles.forEach((role) -> role.setRelationState(MandyConstant.AuditState.CHECKED));
            mandyUserWithRoles.setMyRoles(newMyRoles);

            boolean find = false;
            Long oldCurrentRoleId = mandyUserWithRoles.getCurrentRoleId();
            for (MandyUserWithRolesMyRoles newMyRole : newMyRoles) {
                if ( newMyRole.getId().equals(oldCurrentRoleId)) {
                    find = true;
                    break;
                }
            }

            //用户的当前角色不在新的角色集中, 要替换掉
            if (!find) {
                mandyUserWithRoles.setCurrentRoleId(newMyRoles.get(0).getId());
            }
        }

        setMandyUserAuditInfo(mandyUser);
        mandyUser.setAuditState(MandyConstant.AuditState.CHECKED);
        mandyUserMapper.updateByPrimaryKey(mandyUser);

        //返回给前端
        mandyUserWithRoles.setDepartmentId(mandyUser.getDepartmentId());
        mandyUserWithRoles.setDepartmentName(mandyUser.getDepartmentName());
        mandyUserWithRoles.setDepartmentPath(mandyUser.getDepartmentPath());
        mandyUserWithRoles.setNewDepartmentId(mandyUser.getNewDepartmentId());
        mandyUserWithRoles.setNewDepartmentName(mandyUser.getNewDepartmentName());
        mandyUserWithRoles.setIzEnabled(mandyUser.getIzEnabled());
        mandyUserWithRoles.setNewIsEnabled(mandyUser.getNewIsEnabled());
        mandyUserWithRoles.setUserState(mandyUser.getUserState());
        mandyUserWithRoles.setAuditState(mandyUser.getAuditState());
        mandyUserWithRoles.setAuditUserId(mandyUser.getAuditUserId());
        mandyUserWithRoles.setAuditUserName(mandyUser.getAuditUserName());
        mandyUserWithRoles.setAuditTime(mandyUser.getAuditTime());

        //清除相关的缓存
        mandyCacheService.cacheEvictGetMandyUserByName(mandyUserWithRoles.getUsername());
        mandyCacheService.cacheEvictListUserRolesByUserId(mandyUserWithRoles.getId());

        return mandyUserWithRoles;
    }

    @Override
    @Transactional
    public MandyUserWithRoles userNewRoles(MandyUserWithRoles  mandyUserWithRoles) {
        MandyUserRoleExample mandyUserRoleExample = new MandyUserRoleExample();
        mandyUserRoleExample.createCriteria().andUserIdEqualTo(mandyUserWithRoles.getId())
                .andAuditStateEqualTo(MandyConstant.AuditState.UNCHECKED);
        mandyUserRoleMapper.deleteByExample(mandyUserRoleExample);

        for (MandyUserWithRolesMyRoles roles: mandyUserWithRoles.getMyRoles() ) {
            MandyUserRole mandyUserRole = new MandyUserRole();
            mandyUserRole.setUserId(mandyUserWithRoles.getId());
            mandyUserRole.setRoleId(roles.getId());
            mandyUserRole.setAuditState(MandyConstant.AuditState.UNCHECKED);
            mandyUserRoleMapper.insert(mandyUserRole);
        }



        //更新用户状态
        mandyUserWithRoles.setAuditState(MandyConstant.AuditState.UPDATING);
        mandyUserMapper.updateByPrimaryKey(mandyUserWithRoles);

        MandyUserWithRolesParam mandyUserWithRolesParam = new MandyUserWithRolesParam();
        mandyUserWithRolesParam.setId(mandyUserWithRoles.getId());
        List<MandyUserWithRoles> users = mandyUserWithRolesDao.listUser(mandyUserWithRolesParam);
        if (null != users && users.size() == 1 ) {
            return mandyUserWithRolesDao.listUser(mandyUserWithRolesParam).get(0);
        }
        return null;
    }

    @Override
    public List<MandyParameter> getAllParameters(){
        return mandyParameterMapper.selectByExample(null);
    }


}
